﻿using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Content;

namespace PrisonStep
{
    public class Dalek
    {

        #region MemberVariables

        private enum States { Stance, Walkstart, Walkloop, Tantrum, CatchEat, Ob };

        private float dalekVel = 2;

        /// <summary>
        /// The animation model for dalek
        /// </summary>
        private AnimatedModel mDalek;

        /// <summary>
        /// Our Game
        /// </summary>
        private PrisonGame mGame;

        /// <summary>
        /// Player location in the prison. Only x/z are important. y still stay zero
        /// unless we add some flying or jumping behavior later on.
        /// </summary>
        private Vector3 location = new Vector3(849, 0, -582);

        /// <summary>
        /// The player orientation as a simple angle
        /// </summary>
        private float orientation = 0.0f;

        /// <summary>
        /// The player transformation matrix. Places the player where they need to be.
        /// </summary>
        private Matrix transform = Matrix.Identity;

        /// <summary>
        /// Our initial state
        /// </summary>
        private States mState = States.Stance;

        private const float mAnimationTime = 1.0f;

        private float mElapsedTime;

        private BoundingCylinder mBoundingCyl = null;

        /// <summary>
        /// The timer will fire every 5 seconds or so
        /// </summary>
        private float mSpitTimer = 5.0f;

        private Spit mSpit;

        private float mPlungerAngle = 0;

        private int mPlungerDirection = 1;
        #endregion

        #region Properties

        public Vector3 Location { get { return location; } set { location = value; } }

        public Matrix DalekHead
        {
            get { SetTransform(); return mDalek.GetBoneTransforms("Head"); }
            set { mDalek.SetBoneTransforms("Head", value); mDalek.ComputeAbsoluteTransforms(); }
        }

        public Matrix DalekEye
        {
            get { SetTransform(); return mDalek.GetBoneTransforms("Eye"); }
            set { mDalek.SetBoneTransforms("Eye", value); mDalek.ComputeAbsoluteTransforms(); }
        }

        public Matrix DalekArm
        {
            get { SetTransform(); return mDalek.GetBoneTransforms("Arm2"); }
            set { mDalek.SetBoneTransforms("Arm2", value); mDalek.ComputeAbsoluteTransforms(); }
        }

        public Matrix DalekPlunger
        {
            get { SetTransform(); return mDalek.GetBoneTransforms("PlungerArm"); }
            set { mDalek.SetBoneTransforms("PlungerArm", value); mDalek.ComputeAbsoluteTransforms(); }
        }

        public Matrix HeadTransform { get { mDalek.ComputeAbsoluteTransforms(); return mDalek.AbsoTransforms("Head") * transform * Matrix.CreateRotationY(-orientation + (float)Math.PI / 2); } }

        public BoundingCylinder BoundingCyl { get { ComputeBoundingCylinder();  return mBoundingCyl; } }

        public float SlimeWeight { get { return mDalek.SlimeWeight; } set { mDalek.SlimeWeight = value; } }

        #endregion


        public Dalek(PrisonGame aGame)
        {
            this.mGame = aGame;
            mDalek = new AnimatedModel(aGame, "Dalek");
            mDalek.Skinned = false;
            mDalek.Region = "R_Section5";
            mDalek.Adjacent = 5;

            mBoundingCyl = new BoundingCylinder(location, 135, 52);

            mElapsedTime = 0.0f;

            this.mSpit = new Spit(aGame);
        }
        private void SetTransform()
        {
            transform = Matrix.CreateRotationY(orientation);
            transform.Translation = location;
        }


        public void LoadContent(ContentManager aContent)
        {
            // Dalek stuff

            mDalek.LoadContent(aContent);

            mSpit.LoadContent(aContent);
        }

        /// <summary>
        /// This function is called to update this component
        /// to the current game time
        /// </summary>
        /// <param name="aGameTime"></param>
        public void Update(GameTime aGameTime)
        {
            double lDeltaTotal = aGameTime.ElapsedGameTime.TotalSeconds;
            // move dalek
            if (mGame.TestRegionNoWall(location + transform.Backward * dalekVel) == "" || mGame.TestRegionNoWall(location + transform.Backward * dalekVel).StartsWith("R_D"))
            {
                orientation += (float)aGameTime.ElapsedGameTime.TotalSeconds * dalekVel;
            }
            else
            {
                location += transform.Backward * dalekVel;
            }

            //Make Dalek's head follow the player
            Vector3 lDalekToPlayer = new Vector3(mGame.Victoria.VictoriaLocation.X - location.X, 0, mGame.Victoria.VictoriaLocation.Z - location.Z);
            DalekHead = Matrix.CreateRotationZ(-(float)Math.Atan2(lDalekToPlayer.Z, lDalekToPlayer.X) - orientation + (float)Math.PI / 2f) *
                        mDalek.GetBindTransforms("Head");

            // Make distruptor follow player
            float tempAngle = -(float)Math.Atan2(mGame.Victoria.VictoriaLocation.Z - location.Z, mGame.Victoria.VictoriaLocation.X - location.X) - orientation + (float)Math.PI / 2f;
            float tempOrientation = -(float)Math.Atan2(mGame.Victoria.VictoriaLocation.Z - location.Z, mGame.Victoria.VictoriaLocation.X - location.X) + (float)Math.PI / 2;
            if (Math.Abs(orientation - tempOrientation) <= 1.8)
                DalekArm = Matrix.CreateRotationZ(tempAngle) * mDalek.GetBindTransforms("Arm2");

            
            // Make plunger move
            if (mPlungerAngle >= -0.3 && mPlungerAngle <= 0.3f)
            {
                mPlungerAngle += (float)mPlungerDirection * (float)lDeltaTotal;
            }
            else
            {
                mPlungerDirection *= -1;
                mPlungerAngle += (float)mPlungerDirection * (float)lDeltaTotal;
            }
            DalekPlunger = Matrix.CreateRotationZ(mPlungerAngle) * mDalek.GetBindTransforms("PlungerArm");

            
            if (mSpitTimer <= 0)
            {
                mSpitTimer = 5.0f;
                Spit();
            }
            mSpitTimer -= (float)aGameTime.ElapsedGameTime.TotalSeconds;

            
            mDalek.Update(lDeltaTotal);

            mSpit.Update(aGameTime);

        }

        /// <summary>
        /// This function is called to draw this game component
        /// </summary>
        /// <param name="aGraphics">Devicet to draw the model on.</param>
        /// <param name="aGameTime">Currentgame time.</param>
        /// <param name="aTransform">Transform that puts the model where we want it.</param>
        public void Draw(GraphicsDeviceManager aGraphics, GameTime aGameTime)
        {
            SetTransform();
            mDalek.Draw(aGraphics, aGameTime, transform);

            mSpit.Draw(aGraphics, aGameTime);
        }

        private void ComputeBoundingCylinder()
        {
            mBoundingCyl.Location = location;
            
        }
        private void Spit()
        {
            mSpit.AddSpit(HeadTransform);
        }
    }
}
